
import re
import random

from web.utils.enc import set_md5
from web.utils.bootstrap import BootStrapForm

from web import models
from django import forms
from django.core.exceptions import ValidationError
from django.conf import settings
from django.db.models import Q

from libs.tengxunyun.sms import MySmsSender
from django_redis import get_redis_connection

def mobile_validate(value):
    mobile_re = re.compile(r'^(13[0-9]|15[012356789]|17[678]|18[0-9]|14[57])[0-9]{8}$')
    if not mobile_re.match(value):
        raise ValidationError('后端说：手机号码格式错误')


class RegisterModelForm(BootStrapForm, forms.ModelForm):

    phone = forms.CharField(
        label='手机号',
        validators=[mobile_validate, ]
    )

    password = forms.CharField(

        label='密码',
        widget=forms.PasswordInput,
        max_length=8,
        min_length=4,
        error_messages={
            'max_length': '最大长度不能超过8位',
            'min_length': '最小长度不能低于4位',
        }
    )

    confirm_password = forms.CharField(
        label='确认密码',
        widget=forms.PasswordInput,
        max_length=8,
        min_length=4,
        error_messages={
            'max_length': '最大长度不能超过8位',
            'min_length': '最小长度不能低于4位',
        }
    )
    sms_code = forms.CharField(label='验证码')

    class Meta:
        model = models.UserInfo
        # fields = '__all__'
        # 调整字段显示顺序
        fields = ['username', 'email', 'phone', 'password']

    # def __init__(self,*args,**kwargs):
    #     super().__init__(*args,**kwargs)
    #     for name, field in self.fields.items():
    #
    #         field.widget.attrs.update({'class': 'form-control'})
    #         field.widget.attrs.update({'placeholder': '请输入'+field.label})

    # 用户名唯一性校验
    def clean_username(self):
        username = self.cleaned_data.get('username', '')
        exists = models.UserInfo.objects.filter(username=username).exists()
        if exists:
            # self.add_error('username','该用户名已存在')
            raise ValidationError('该用户名已存在')

        return username

    # 邮箱唯一性验证
    def clean_email(self):
        email = self.cleaned_data.get('email', '')
        exists = models.UserInfo.objects.filter(email=email).exists()
        if exists:
            # self.add_error('username','该用户名已存在')
            raise ValidationError('该邮箱已被注册')

        return email

    # 手机号唯一性验证
    def clean_phone(self):
        phone = self.cleaned_data.get('phone', '')
        exists = models.UserInfo.objects.filter(phone=phone).exists()
        if exists:
            # self.add_error('username','该用户名已存在')
            raise ValidationError('该手机号已被注册')

        return phone


    # 对密码进行加密
    def clean_password(self):
        password = self.cleaned_data.get('password', '')
        print(">>>>>>", set_md5(password))
        return set_md5(password)

    # self.cleaned_data['password'] = set_md5(password)
    # 两次密码比较验证
    def clean(self):
        p1 = self.cleaned_data.get('password', '')
        p2 = set_md5(self.cleaned_data.get('confirm_password',''))
        # p2 = self.cleaned_data.get('confirm_password')
        print('>>>>',p1,p2)
        if p1.strip() != p2.strip():

            self.add_error('confirm_password', '两次密码不一致')
        # self.cleaned_data['password'] = set_md5(p1)
        return self.cleaned_data

    # 验证码校验
    def clean_sms_code(self):

        phone = self.cleaned_data.get('phone')
        conn = get_redis_connection('sms_code')
        sms_code = self.cleaned_data.get('sms_code')
        redis_code = conn.get(phone)

        if not redis_code:
            raise ValidationError('验证码已失效')
        redis_code = redis_code.decode('utf-8')
        if sms_code.strip() != redis_code:
            raise ValidationError('验证码输入有误')

        return redis_code

# 获取验证码的form类
class SendSmsForm(forms.Form):
    phone = forms.CharField(
        label='手机号',
        validators=[mobile_validate, ]
    )

    # 重新init方法，接受额外参数
    def __init__(self, request, *args, **kwargs):

        super().__init__(*args, **kwargs)
        self.request = request  # 封装request对象

    def clean_phone(self):
        # self.cleaned_data['phone']
        phone = self.cleaned_data.get('phone')
        # 校验短信模板
        tpl = self.request.GET.get('tpl')  # register--login

        try:
            tpl_id = settings.SMS_TEMPLATE_ID[tpl]

        except:
            raise ValidationError('短信模板错误！！！')

        # 手机号唯一性校验
        obj_list = models.UserInfo.objects.filter(phone=phone)

        # 获取短信验证码时，区分一下是注册还是登陆
        if tpl == 'register':
            if obj_list.exists():
                raise ValidationError('该手机号已经注册过了')

        elif tpl == 'login':
            if not obj_list.exists():
                raise ValidationError('手机号未注册，请先注册！')


        # 手机号和tpl的校验都通过了
        # 发送短信
        #1 校验该手机号是不是已经发送过短信了，是不是在有效期内
        conn = get_redis_connection('sms_code')
        ret = conn.get(phone)  #get不到返回None
        if ret:
            raise ValidationError('已经发过了大哥，你慢点')
        #1 生成验证码
        sms_code = '%06d' % random.randint(1, 999999)
        #2 将验证码保存到redis当中  111222 -- 1383838383

        conn.set(phone, sms_code, ex=settings.SMS_CODE_EXPIRE)  #

        sms_obj = MySmsSender()
        send_status = sms_obj.send(phone, tpl_id, sms_code)
        print(send_status)
        if send_status != 'Ok':
            raise ValidationError('后台说：短信发送失败！')

        return phone


# 短信登录的form类
class LoginSmsForm(BootStrapForm, forms.Form):
    phone = forms.CharField(
        label='手机号',
        validators=[mobile_validate, ]
    )
    sms_code = forms.CharField(label='验证码')

    # 手机号唯一性校验
    def clean_phone(self):
        phone = self.cleaned_data.get('phone')
        exists = models.UserInfo.objects.filter(phone=phone).exists()
        if not exists:
            raise ValidationError('手机号不存在，不要乱搞')

        return phone

        # 验证码校验
    def clean_sms_code(self):

        phone = self.cleaned_data.get('phone')
        conn = get_redis_connection('sms_code')
        sms_code = self.cleaned_data.get('sms_code')
        redis_code = conn.get(phone)

        if not redis_code:
            raise ValidationError('验证码已失效')
        redis_code = redis_code.decode('utf-8')
        if sms_code.strip() != redis_code:
            raise ValidationError('验证码输入有误')

        return redis_code


# 手机号或者邮箱登录的form类

class LoginForm(BootStrapForm, forms.Form):

    username = forms.CharField(label='手机号或者邮箱')
    password = forms.CharField(label='密码',widget=forms.PasswordInput,)

    image_code = forms.CharField(label='验证码')

    def __init__(self,request, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.request = request

    def clean_password(self):
        pwd = self.cleaned_data.get('password')
        return set_md5(pwd)


    # 图片验证码的验证
    # 用户输入的和后台保存的要一致
    def clean_image_code(self):
        user_code = self.cleaned_data.get('image_code')
        session_code = self.request.session.get('image_code')
        # 判断session_code是否已经失效
        if not session_code:
            raise ValidationError('验证码已过期，请重新获取')

        if user_code.strip().upper() != session_code.upper():
            raise ValidationError('扣眼珠子！')

        return session_code

    def clean(self):

        pwd = self.cleaned_data.get('password')
        uname = self.cleaned_data.get('username')
        exists = models.UserInfo.objects.filter(Q(phone=uname)|Q(email=uname),password=pwd).exists()
        if not exists:
            self.add_error('username', '用户名或者密码有误！')

        return self.cleaned_data

